package curses

// struct ldat{};
// struct _win_st{};
// #define _Bool int
// #define NCURSES_OPAQUE 1 
// #include <curses.h>
// enum { MY_RMP = REPORT_MOUSE_POSITION, MY_AME = ALL_MOUSE_EVENTS };
import "C"

import (
	"fmt"
	"os"
	"unsafe"
)

type void unsafe.Pointer

type Window C.WINDOW

type CursesError struct {
	message string
}

func (ce CursesError) String() string {
	return ce.message
}

// Cursor options.
const (
	CURS_HIDE = iota
	CURS_NORM
	CURS_HIGH
)

const (
    ACS_ULCORNER     = 4194412
    ACS_LLCORNER     = 4194413
    ACS_URCORNER     = 4194411
    ACS_LRCORNER     = 4194410
    ACS_LTEE         = 4194420
    ACS_RTEE         = 4194421
    ACS_BTEE         = 4194422
    ACS_TTEE         = 4194423
    ACS_HLINE        = 4194417
    ACS_VLINE        = 4194424
    ACS_PLUS         = 4194414
    ACS_S1           = 4194415
    ACS_S9           = 4194419
    ACS_DIAMOND      = 4194400
    ACS_CKBOARD      = 4194401
    ACS_DEGREE       = 4194406
    ACS_PLMINUS      = 4194407
    ACS_BULLET       = 4194430
    ACS_LARROW       = 4194348
    ACS_RARROW       = 4194347
    ACS_DARROW       = 4194350
    ACS_UARROW       = 4194349
    ACS_BOARD        = 4194408
    ACS_LANTERN      = 4194409
    ACS_BLOCK        = 4194352
    ACS_S3           = 4194416
    ACS_S7           = 4194418
    ACS_LEQUAL       = 4194425
    ACS_GEQUAL       = 4194426
    ACS_PI           = 4194427
    ACS_NEQUAL       = 4194428
    ACS_STERLING     = 4194429
)

// Pointers to the values in curses, which may change values.
var Cols *int = nil
var Rows *int = nil

var Colors *int = nil
var ColorPairs *int = nil

var Tabsize *int = nil

// The window returned from C.initscr()
var Stdwin *Window = nil

// Initializes gocurses
func init() {
        Stdwin = (*Window)(C.initscr())
	Cols = (*int)(void(&C.COLS))
	Rows = (*int)(void(&C.LINES))
	Colors = (*int)(void(&C.COLORS))
	ColorPairs = (*int)(void(&C.COLOR_PAIRS))
	Tabsize = (*int)(void(&C.TABSIZE))
}

func InitColor( c, r, g, b int ) {
    _ = C.init_color( C.short(c), C.short(r), C.short(g), C.short(b) )
}

func Initscr() (*Window, os.Error) {
	// Stdwin = (*Window)(C.initscr())
	if Stdwin == nil { return nil, CursesError{"Initscr failed"} } 
	return Stdwin, nil
}

func Newwin(rows int16, cols int16, starty int16, startx int16) *Window {
	nw := (*Window)(C.newwin(C.int(rows), C.int(cols), C.int(starty), C.int(startx)))
	return nw
}

func (win *Window) Subwin(rows int16, cols int16, starty int16, startx int16) *Window {
	sw := (*Window)(C.subwin((*C.WINDOW)(win), C.int(rows), C.int(cols), C.int(starty), C.int(startx)))
	return sw
}

func (win *Window) Derwin(rows int16, cols int16, starty int16, startx int16) *Window {
	dw := (*Window)(C.derwin((*C.WINDOW)(win), C.int(rows), C.int(cols), C.int(starty), C.int(startx)))
	return dw
}

func Start_color() os.Error {
	if int(C.has_colors()) == 0 { return CursesError{"terminal does not support color"} }
	C.start_color()
	return nil
}

func Init_pair(pair int16, fg int16, bg int16) os.Error {
	if C.init_pair(C.short(pair), C.short(fg), C.short(bg)) == 0 { return CursesError{"Init_pair failed"} }
	return nil
}

func Color_pair(pair int) int32 {
	return int32(C.COLOR_PAIR(C.int(pair)))
}

func Noecho() os.Error {
	if int(C.noecho()) == 0 { return CursesError{"Noecho failed"} }
	return nil
}

func Echo() os.Error {
	if int(C.noecho()) == 0 { return CursesError{"Echo failed"} }
	return nil
}

func Curs_set(c int) os.Error {
	if C.curs_set(C.int(c)) == 0 { return CursesError{"Curs_set failed"} }
	return nil
}

func Nocbreak() os.Error {
	if C.nocbreak() == 0 { return CursesError{"Nocbreak failed"} }
	return nil
}

func Raw() os.Error {
    if C.raw() == 0 { return CursesError{"Raw failed"} }
    return nil
}

func Cbreak() os.Error {
	if C.cbreak() == 0 { return CursesError{"Cbreak failed"} }
	return nil
}

func Endwin() os.Error {
	if C.endwin() == 0 { return CursesError{"Endwin failed"} }
	return nil
}

func Timeout(n int) {
    C.timeout(C.int(n))
}

var sortofnull *int

func (win *Window) ChAttr(x, y int, n int, attr int, colour int ) {
    C.mvwchgat( (*C.WINDOW)(win), C.int(y), C.int(x), C.int(n), C.attr_t(attr), C.short(colour), unsafe.Pointer(sortofnull) )
}

func (win *Window) Getch() int {
	return int(C.wgetch((*C.WINDOW)(win)))
}

func MouseEvent() (mx, my, mbuttons int) {
    var e C.MEVENT
    C.getmouse( &e )
    mx, my, mbuttons = int(e.x), int(e.y), int(e.bstate)
    return
}

func EnableMouse() {
    var oldMask C.mmask_t
    newMask := C.mmask_t( C.MY_AME | C.MY_RMP )
    C.mousemask( newMask, &oldMask )
}

func (win *Window) Addch(x, y int, c int32, flags int32) {
	C.mvwaddch((*C.WINDOW)(win), C.int(y), C.int(x), C.chtype(c) | C.chtype(flags))
}

// Since CGO currently can't handle varg C functions we'll mimic the
// ncurses addstr functions.
func (win *Window) Addstr(x, y int, str string, flags int32, v ...interface{} ) {
	newstr := fmt.Sprintf(str, v...)
	win.Move(x, y)
	for i := 0; i < len(newstr); i++ {
		C.waddch((*C.WINDOW)(win), C.chtype(newstr[i]) | C.chtype(flags))
	}
}

var naff int

func (w *Window) SetAttributeRun(x, y int, run int, attrib int32, cindex int ) {
    C.mvwchgat( (*C.WINDOW)(w), C.int(y), C.int(x), C.int(run), C.attr_t(attrib), C.short(cindex), (unsafe.Pointer)(&naff) )
}

func (w *Window) SetAttributes( flags int ) {
    C.wattron( (*C.WINDOW)(w), C.int(flags) )
}

func (w *Window) RemoveAttributes( flags int ) {
    C.wattroff( (*C.WINDOW)(w), C.int(flags) )
    }

// Normally Y is the first parameter passed in curses.
func (win *Window) Move(x, y int) {
	C.wmove((*C.WINDOW)(win), C.int(y), C.int(x))
}

func (w *Window) Keypad(tf bool) os.Error {
	var outint int
	if tf == true {outint = 1}
	if tf == false {outint = 0}
	if C.keypad((*C.WINDOW)(w), C.int(outint)) == 0 {
		return CursesError{"Keypad failed"}
	}
	return nil
}

func (win *Window) Refresh() os.Error {
	if C.wrefresh((*C.WINDOW)(win)) == 0 {
		return CursesError{"refresh failed"}
	}
	return nil
}

func (win *Window) Redrawln(beg_line, num_lines int) {
	C.wredrawln((*C.WINDOW)(win), C.int(beg_line), C.int(num_lines))
}

func (win *Window) Redraw() {
	C.redrawwin((*C.WINDOW)(win))
}

func (win *Window) Clear() {
	C.wclear((*C.WINDOW)(win))
}

func (win *Window) Erase() {
	C.werase((*C.WINDOW)(win))
}

func (win *Window) Clrtobot() {
	C.wclrtobot((*C.WINDOW)(win))
}

func (win *Window) Clrtoeol() {
	C.wclrtoeol((*C.WINDOW)(win))
}

func (win *Window) Box(verch, horch int16) {
	C.box((*C.WINDOW)(win), C.chtype(verch), C.chtype(horch))
}
